/**
* Copyright (c) By zengqh.
*
* This program is just for fun or demo, in the hope that it  
* will be useful, you can redistribute it and/or modify freely.
*
* Time: 2012/12/16
* File: EnnColor.h
* Blog: http://www.cnblogs.com/zengqh/
**/

#ifndef EnnColor_h__
#define EnnColor_h__

#include "EnnPrerequisites.h"
#include "EnnMath.h"

namespace Enn
{
	/// RGBA color.
	class Color
	{
	public:
		/// Construct with default values (opaque white.)
		Color() :
		  r_(1.0f),
			  g_(1.0f),
			  b_(1.0f),
			  a_(1.0f)
		  {
		  }

		  /// Copy-construct from another color.
		  Color(const Color& color) :
		  r_(color.r_),
			  g_(color.g_),
			  b_(color.b_),
			  a_(color.a_)
		  {
		  }

		  /// Construct from another color and modify the alpha.
		  Color(const Color& color, float a) :
		  r_(color.r_),
			  g_(color.g_),
			  b_(color.b_),
			  a_(a)
		  {
		  }

		  /// Construct from RGB values and set alpha fully opaque.
		  Color(float r, float g, float b) :
		  r_(r),
			  g_(g),
			  b_(b),
			  a_(1.0f)
		  {
		  }

		  /// Construct from RGBA values.
		  Color(float r, float g, float b, float a) :
		  r_(r),
			  g_(g),
			  b_(b),
			  a_(a)
		  {
		  }

		  /// Test for equality with another color.
		  bool operator == (const Color& rhs) const { return RealEqual(r_, rhs.r_) && RealEqual(g_, rhs.g_) && RealEqual(b_, rhs.b_) && RealEqual(a_, rhs.a_); }
		  /// Test for inequality with another color.
		  bool operator != (const Color& rhs) const { return !RealEqual(r_, rhs.r_) || !RealEqual(g_, rhs.g_) || !RealEqual(b_, rhs.b_) || !RealEqual(a_, rhs.a_); }
		  /// Multiply with a scalar.
		  Color operator * (float rhs) const { return Color(r_ * rhs, g_ * rhs, b_ * rhs, a_ * rhs); }
		  /// Add a color.
		  Color operator + (const Color& rhs) const { return Color(r_ + rhs.r_, g_ + rhs.g_, b_ + rhs.b_, a_ + rhs.a_); }

		  /// Add-assign a color.
		  Color& operator += (const Color& rhs)
		  {
			  r_ += rhs.r_;
			  g_ += rhs.g_;
			  b_ += rhs.b_;
			  a_ += rhs.a_;
			  return *this;
		  }

		  /// Return float data.
		  const float* Data() const { return &r_; }
		  /// Return RGB values as a Vector3.
		  Vector3 RGBValues() const { return Vector3(r_, g_, b_); }
		  /// Return approximate intensity.
		  float Intensity() const { return RGBValues().dotProduct(Vector3(0.333f, 0.333f, 0.333f)); }

		  /// Linear interpolation with another color.
		  Color Lerp(const Color& rhs, float t) const
		  {
			  float invT = 1.0f - t;
			  return Color(
				  r_ * invT + rhs.r_ * t,
				  g_ * invT + rhs.g_ * t,
				  b_ * invT + rhs.b_ * t,
				  a_ * invT + rhs.a_ * t
				  );
		  }

		  /// Return color packed to a 32-bit integer. Components are clamped to [0, 1] range.
		  unsigned ToUInt() const
		  {
			  unsigned r = Clamp(((int)(r_ * 255.0f)), 0, 255);
			  unsigned g = Clamp(((int)(g_ * 255.0f)), 0, 255);
			  unsigned b = Clamp(((int)(b_ * 255.0f)), 0, 255);
			  unsigned a = Clamp(((int)(a_ * 255.0f)), 0, 255);
			  return (a << 24) | (b << 16) | (g << 8) | r;
		  }

		  /// Return as a four-dimensional vector.
		  Vector4 ToVector4() const { return Vector4(r_, g_, b_, a_); }

		  /// Return as string.
		  String ToString() const;

		  /// Red value.
		  float r_;
		  /// Green value.
		  float g_;
		  /// Blue value.
		  float b_;
		  /// Alpha value.
		  float a_;

		  /// Opaque white color.
		  static const Color WHITE;
		  /// Opaque yellow color.
		  static const Color YELLOW;
		  /// Opaque red color.
		  static const Color RED;
		  /// Opaque green color.
		  static const Color GREEN;
		  /// Opaque green color.
		  static const Color BLUE;
		  /// Opaque black color.
		  static const Color BLACK;
	};


	/// Color-time pair for color interpolation.
	class ColorFade
	{
	public:
		/// Construct with default color and zero time.
		ColorFade() :
		  time_(0.0f)
		  {
		  }

		  /// Construct with a color and zero time.
		  ColorFade(const Color& color) :
		  color_(color),
			  time_(0.0f)
		  {
		  }

		  /// Construct from a color and time.
		  ColorFade(const Color& color, float time) :
		  color_(color),
			  time_(time)
		  {
		  }

		  /// Return interpolated value with another color-time pair, at the time specified.
		  Color interpolate(const ColorFade& next, float time)
		  {
			  float timeInterval = next.time_ - time_;
			  if (timeInterval > 0.0f)
			  {
				  float t = (time - time_) / timeInterval;
				  return color_.Lerp(next.color_, t);
			  }
			  else
				  return next.color_;
		  }

		  /// Color.
		  Color color_;
		  /// Time.
		  float time_;
	};

}
#endif    /* EnnColor_h__ */